﻿using System;
using System.Runtime.InteropServices;

namespace Wheels
{
    /// <summary>
    /// 提供浮点数和其它数据类型的转换方法。
    /// </summary>
    public static class FloatConversion
    {
        [StructLayout(LayoutKind.Explicit)]
        private struct SinglePayload
        {
            [FieldOffset(0)]
            public Single Single;
            [FieldOffset(0)]
            public Int32 Int32;
            [FieldOffset(0)]
            public UInt32 UInt32;
        }

        [StructLayout(LayoutKind.Explicit)]
        private struct DoublePayload
        {
            [FieldOffset(0)]
            public double Double;
            [FieldOffset(0)]
            public Int64 Int64;
            [FieldOffset(0)]
            public UInt64 UInt64;
        }

        const uint UIntMidPoint = 0x80000000;
        const int IntMidMask = (int)~UIntMidPoint;
        const ulong ULongMidPoint = UIntMidPoint * 0x100000000u;
        const long LongMidMask = (long)~ULongMidPoint;

        #region 64位

        #region 有符号整数

        /// <summary>
        /// 根据给定的双精度浮点数，计算出一个在排序场合与其等价的 64 位有符号整数。
        /// </summary>
        public static long ToSortableInt64(this double value)
        {
            //long payload = *(long*)(&value);
            var payload = new DoublePayload { Double = value }.Int64;

            if (payload < 0)
            {
                payload ^= LongMidMask;
            }

            return payload;
        }

        /// <summary>
        /// 从给定的 64 位有符号整数，计算出其所代表的双精度浮点数。
        /// </summary>
        public static double ToSortableDouble(this long value)
        {
            if (value < 0)
            {
                value ^= LongMidMask;
            }

            return new DoublePayload { Int64 = value }.Double;

            //return *(double*)&value;
        }

        #endregion

        #region 无符号整数

        /// <summary>
        /// 根据给定的双精度浮点数，计算出一个在排序场合与其等价的 64 位无符号整数。
        /// </summary>
        [CLSCompliant(false)]
        public static ulong ToSortableUInt64(this double value)
        {
            //ulong payload = *(ulong*)(&value);
            var payload = new DoublePayload { Double = value }.UInt64;

            if (payload < ULongMidPoint)
            {
                payload ^= ULongMidPoint;
            }
            else
            {
                payload = ~payload;
            }

            return payload;
        }

        /// <summary>
        /// 从给定的 64 位无符号整数，计算出其所代表的双精度浮点数。
        /// </summary>
        [CLSCompliant(false)]
        public static double ToSortableDouble(this ulong value)
        {
            if (value < ULongMidPoint)
            {
                value = ~value;
            }
            else
            {
                value ^= ULongMidPoint;
            }

            return new DoublePayload { UInt64 = value }.Double;

            //return *(double*)(&value);
        }

        #endregion

        #endregion

        #region 32位

        #region 有符号整数

        /// <summary>
        /// 根据给定的单精度浮点数，计算出一个在排序场合与其等价的 32 位有符号整数。
        /// </summary>
        public static int ToSortableInt(this float value)
        {
            //int payload = *(int*)(&value);

            var payload = new SinglePayload { Single = value }.Int32;

            if (payload < 0)
            {
                payload ^= IntMidMask;
            }

            return payload;
        }

        /// <summary>
        /// 从给定的 32 位有符号整数，计算出其所代表的单精度浮点数。
        /// </summary>
        public static float ToSortableSingle(this int value)
        {
            if (value < 0)
            {
                value ^= IntMidMask;
            }

            return new SinglePayload { Int32 = value }.Single;

            //return *(float*)&value;
        }

        #endregion

        #region 无符号整数

        /// <summary>
        /// 根据给定的单精度浮点数，计算出一个在排序场合与其等价的 32 位无符号整数。
        /// </summary>
        [CLSCompliant(false)]
        public static uint ToSortableUInt(this float value)
        {
            //uint payload = *(uint*)(&value);

            var payload = new SinglePayload { Single = value }.UInt32;

            if (payload < UIntMidPoint)
            {
                payload ^= UIntMidPoint;
            }
            else
            {
                payload = ~payload;
            }

            return payload;
        }

        /// <summary>
        /// 从给定的 32 位无符号整数，计算出其所代表的单精度浮点数。
        /// </summary>
        [CLSCompliant(false)]
        public static float ToSortableSingle(this uint value)
        {
            if (value < UIntMidPoint)
            {
                value = ~value;
            }
            else
            {
                value ^= UIntMidPoint;
            }

            return new SinglePayload { UInt32 = value }.Single;

            //return *(float*)(&value);
        }

        #endregion

        #endregion

    }
}
